const http = require('http')
const path = require('path')
const fs = require('fs')
const async = require('async')
//
const Record = require('./record')
//
const url = 'http://static.micheliafigo.xyz/books/1581347142049.jpeg'
const targetFile = path.join(__dirname, '../file/image.jpeg')
const recordFile = path.join(__dirname, '../file/image.ce')
const SINGLE = 1024 * 50
// const SINGLE = 80000

class Chunk {
  constructor() {
    this.record = null
    this.req = null
    this.reqGets = []
    this.begin()
  }

  begin() {
    this.deleteFile(targetFile)
    //
    this.req = this.httpHEAD()
    this.req.end()
  }

  deleteFile(filePath) {
    // delete file
    let file = fs.existsSync(filePath)
    file &&
      fs.unlinkSync(filePath, function(err) {
        if (err) throw err
      })
  }

  httpGet(index, start, end, size, callback) {
    let getHttp = http.get(
      url,
      {
        headers: {
          Range: `bytes=${start}-${end}`,
          'If-Range': 'FF70503A7175D736D973ECE83554EE84',
          'Content-Type': 'text/plain',
          'Content-length': 0
        }
      },
      response => {
        let _buf
        // onData
        response.on('data', chunk => {
          chunk = Buffer.from(chunk) //监听数据响应，拼接数据片段
          if (!_buf) {
            _buf = chunk
          } else {
            let _length = _buf.length + chunk.length // 可以省略
            _buf = Buffer.concat([_buf, chunk], _length)
          }
        })
        // end
        let that = this
        response.on('end', function() {
          // 中止

          if (response.aborted) return

          // write
          // console.log(`start:${start},end:${end}`)
          fs.open(targetFile, 'as+', function(err, fd) {
            if (err) throw err
            // console.log(_buf)
            let written = fs.writeSync(fd, _buf, 0, _buf.length, start)
            // console.log(written, size, index)
            that.record.setChunkTag(index)
            callback()
          })
        })

        response.on('error', function(err) {
          console.log(err)
        })
      }
    )
    this.reqGets.push(getHttp)
  }

  httpHEAD() {
    return http.request(url, { method: 'HEAD' }, response => {
      let { 'content-length': contentLength, etag } = response.headers
      this.record = new Record(recordFile, etag, contentLength, SINGLE)
      // test demo
      setTimeout(() => {
        this.test()
      }, 3000)

      // console.log(response.headers)
      response.on('end', () => {})
    })
  }

  chunkGet() {
    this.reqGets = []
    let length = this.record.chunks.length
    // chunk-download
    // for (let i = 0; i < length; i++) {
    //   let { index, size, begin, end, read } = this.record.chunks[i]
    //   // console.log(`start:${begin},end:${end}`)
    //   let getHttp = this.httpGet(index, begin, end, size)
    //   //
    //   this.reqGets.push(getHttp)
    // }
    async.mapLimit(this.record.chunks, 2, (chunk, callback) => {
      let { index, size, begin, end, read } = chunk
      this.httpGet(index, begin, end, size, callback)
    })
  }

  test() {
    this.record.readRecordFile()
    this.chunkGet()
    // 模拟中断
    setTimeout(() => {
      this.reqGets.map(get => {
        if (get) {
          try {
            get.abort()
          } catch (e) {}
        }
      })
      //  dely re down load
      setTimeout(() => {
        this.reDownLoad()
      }, 3000)
    }, 100)
  }

  reDownLoad() {
    let ranges = this.record.checkNullChunk()
    console.log(ranges)
    this.reqGets = []

    async.mapLimit(
      ranges,
      1,
      (chunkIndex, callback) => {
        let { index, size, begin, end, read } = this.record.chunks[chunkIndex]
        this.httpGet(index, begin, end, size, callback)
      },
      function(err, result) {
        console.log('final:')
        console.log(result)
      }
    )
    // console.log(range)
  }
}

let buf = new Chunk()
